package com.springboot.demo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.JsonObject;
import com.springboot.demo.entity.*;
import com.springboot.demo.entity.data.MsgData;
import com.springboot.demo.entity.vo.DeviceClusterUser;
import com.springboot.demo.entity.vo.UserDeviceVO;
import com.springboot.demo.exception.BusinessException;
import com.springboot.demo.mapper.*;
import com.springboot.demo.service.DeviceService;
import com.springboot.demo.service.InboxService;
import com.springboot.demo.service.UserService;
import com.springboot.demo.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author wubc683
 * @desc
 * @date 2021-09-13 9:17
 */
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    DeviceMapper deviceMapper;
    @Autowired
    SceneMapper sceneMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    InboxMapper inboxMapper;
    @Autowired
    PageUtils pageUtils;
    @Autowired
    UserService userService;
    @Autowired
    InboxService inboxService;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;

    // 设备排序字段
    private static String[] DEVICESORTFIELD = {"id", "deviceName", "createDate", "address"};
    private static String[] MICODEVICESORTFIELD = {"deviceId", "deviceName", "devClusterName", "online", "role",
            "isImported"};

    @Override
    public DeviceCluster getDevClusterInfo(Long ownerId, Long cid) {
        // 检查设备群是否存在
        DeviceCluster deviceCluster = deviceMapper.getDevClusterInfoAndUserRole(ownerId, cid);
        if (deviceCluster == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        // 检查用户是否有此设备群
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(ownerId, cid);
        if (devClusterUserRole == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        }
        return deviceCluster;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createDevCluster(Long ownerId, DeviceCluster deviceCluster) {
        // 用户最多创建设备群500个
        Integer devClusterCount = deviceMapper.getDevClusterCount(ownerId);
        if (devClusterCount.compareTo(Constant.DEVICE_CLUSTER_MAX_COUNT) >= 0) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_COUNT_LIMIT);
        }
        // 检查设备设备群名在mico pc服务器是否重复
        Long devClusterIdByNameFromMico = deviceMapper.getDevClusterIdByNameFromMico(deviceCluster.getName());
        if (devClusterIdByNameFromMico != null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NAME_DUPLICATE);
        }
        // 检查设备设备群名在mico 网页服务器是否重复
        Long devClusterIdByName = deviceMapper.getDevClusterIdByName(deviceCluster.getName());
        if (devClusterIdByName != null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NAME_DUPLICATE);
        }
        deviceCluster.setCreateDate(new Date());
        deviceMapper.saveDevClusterInfo(deviceCluster);
        deviceMapper.saveUserDevClusterInfo(ownerId, deviceCluster.getId(), Constant.DevClusterRole.OWNER);
        deviceMapper.saveDevClusterInfoInMico(deviceCluster);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDevCluster(Long ownerId, DeviceCluster deviceCluster) {
        // 检查设备群是否存在
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(deviceCluster.getId());
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(ownerId, deviceCluster.getId());
        // 检查用户是否拥有设备群
        if (devClusterUserRole == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        }
        // 检查是否是设备群的管理员或者群主
        if (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER) && !devClusterUserRole.equals(Constant.DevClusterRole.ADMIN)) {
            throw new BusinessException(ResponseResult.DEV_CLUSTER_ROLE_FORBIDDEN);
        }
        // 检查设备群名是否重复
        Long devClusterIdByNameFromMico =
                deviceMapper.getDevClusterIdByOldNameAndNameFromMico(devClusterInfo.getName(), deviceCluster.getName());
        if (devClusterIdByNameFromMico != null) {
            throw new BusinessException(ResponseResult.DEV_CLUSTER_NAME_REPEAT);
        }
        deviceMapper.updateDevCluster(deviceCluster);
        deviceMapper.updateDevClusterinMico(devClusterInfo.getName(), deviceCluster.getName(), deviceCluster.getDescription());
    }

    @Override
    public PageResult getAllDevClusterInfo(PageRequest pageRequest, Long ownerId) {
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<DeviceCluster> allDevClusterInfo = deviceMapper.getAllDevClusterInfo(ownerId);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(allDevClusterInfo));
    }

    @Override
    public PageResult getDevClusterUserInfo(PageRequest pageRequest, Long ownerId, Long cid) {
        // 检查用户是否有次设备群
        getDevClusterInfo(ownerId, cid);
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<DeviceClusterUser> devClusterUserInfo = deviceMapper.getDevClusterUserInfo(ownerId, cid);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(devClusterUserInfo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delDevCluster(Long ownerId, Long clusterId) {
        // 检查设备群是否存在
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(clusterId);
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(ownerId, clusterId);
        // 检查用户是否拥有设备群
        if (devClusterUserRole == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        }
        // 检查是否是设备群的群主
        if (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER)) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_USER_NOT_OWNER);
        }
        // 检查设备群是否还有设备
        List<Device> devClusterDevInfo = deviceMapper.getDevClusterAllDevInfo(clusterId);
        if (devClusterDevInfo.size() != 0) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EMPTY);
        }
        deviceMapper.delDevClusterInfo(clusterId);
        deviceMapper.delDevClusterUserInfo(clusterId);
        deviceMapper.delDevClusterInfoInMico(devClusterInfo.getName());
    }

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void transferDevCluster(Long ownerId, String username, Long clusterId) {
//        // 检查设备群是否存在
//        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(clusterId);
//        if (devClusterInfo == null) {
//            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
//        }
//        // 检查是否是设备群的群主
//        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(ownerId, clusterId);
//        // 检查用户是否拥有设备群
//        if (devClusterUserRole == null) {
//            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
//        }
//        if (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER)) {
//            throw new BusinessException(ResponseResult.FORBIDDEN);
//        }
//        // 检查被移交用户是否是设备群管理员,且是关联账号
//        User ownerUser = userService.getUserInfoById(ownerId);
//        User transferUser = userMapper.getUserByUsername(username);
//        if (transferUser == null) {
//            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
//        }
//        if (ownerUser.equals(transferUser)) {
//            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_CAN_NOT_TRANFER_YOURSELF);
//        }
//        userService.checkUserRelative(ownerUser, transferUser);
//        // 检查被移交者是否在设备群内
//        Integer devClusterUserRole1 = deviceMapper.getDevClusterUserRole(transferUser.getId(), clusterId);
//        if (devClusterUserRole1 == null) {
//            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
//        }
//        if (!devClusterUserRole1.equals(Constant.DevClusterRole.ADMIN)) {
//            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_TRANSFER_NOT_ADMIN);
//        }
//        // 交换移交双方角色
//        deviceMapper.updateDevClusterUserInfo(ownerId, clusterId, Constant.DevClusterRole.ADMIN);
//        deviceMapper.updateDevClusterUserInfo(transferUser.getId(), clusterId, Constant.DevClusterRole.OWNER);
//        jsonObject.put("devClusterName", devClusterInfo.getName());
//        jsonObject.put("devClusterOwner", ownerUser.getUsername());
//        String content = ""
//        Inbox inbox = new Inbox(transferUser.getId(), Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE,
//                jsonObject.toString());
//        inboxMapper.saveInbox(inbox);
//        simpMessagingTemplate.convertAndSendToUser(transferUser.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
//    }

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void applyTransferDev2DevCluster(Long ownerId, String username, Long clusterId, String name,
//                                            List<Long> deviceIds) {
//        // 检查设备群是否存在
//        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(clusterId);
//        if (devClusterInfo == null) {
//            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED, "设备群id：" + clusterId);
//        }
//        // 检查被移交设备群是否存在
//        DeviceCluster devClusterInfoByName = deviceMapper.getDevClusterInfoByName(name);
//        if (devClusterInfoByName == null) {
//            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED, "设备群名：" + name);
//        }
//        // 检查被移交设备群是否就是移交设备群
//        if (devClusterInfoByName.getId().equals(clusterId)) {
//            throw new BusinessException(ResponseResult.DEVICE_ALREADY_IN_CLUSTER);
//        }
//        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(ownerId, clusterId);
//        // 检查用户是否拥有设备群
//        if (devClusterUserRole == null) {
//            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
//        }
//        // 检查是否是移交设备群的群主
//        if (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER)) {
//            throw new BusinessException(ResponseResult.DEV_CLUSTER_ROLE_FORBIDDEN);
//        }
//        // 获取被移交设备群群主id
//        Long userId = deviceMapper.getDevClusterUserId(devClusterInfoByName.getId(), Constant.DevClusterRole.OWNER);
//        // 检查设备群用户是否是关联关系
//        User user1 = userService.getUserInfoById(ownerId);
//        User user2 = userService.getUserInfoById(userId);
//        userService.checkUserRelative(user1, user2);
//        // 检查设备是否都存在
//        List<Long> deviceIdByCid = deviceMapper.getDeviceIdByCid(clusterId);
//        for (Long id : deviceIds) {
//            if (!deviceIdByCid.contains(id)) {
//                throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED);
//            }
//        }
////         检查消息是否重复发送
////        String sign = "/devCluster/devices/devCluster/" + ownerId + clusterId + name + deviceIds;
////        String md5 = DigestUtils.md5Hex(sign.getBytes());
////        Inbox msgInfoByUniqueSign = inboxMapper.getMsgInfoByUniqueSign(md5);
////        if (msgInfoByUniqueSign != null) {
////            return;
////        }
//        Inbox inbox = new Inbox();
//        inbox.setType(Constant.MsgType.EVENT);
//        inbox.setCreateDate(new Date());
//        inbox.setReaded(Constant.Msg.UNREADED);
//        inbox.setCode(Constant.WEBSOCKETCMD.APPLY_TRANSFER_DEVICE_TO_DEVICE_CLUSTER);
//        List<String> devNames = deviceMapper.getDevNamesByIds(deviceIds);
//        JSONObject json = new JSONObject();
//        json.put("applyUsername", username);
//        json.put("deviceClusterName", devClusterInfo.getName());
//        json.put("deviceNames", devNames);
//        inbox.setContent(json.toString());
//        inbox.setNeedReply(true);
////        inbox.setUniqueSign(md5);
//        inbox.setReplyState(Constant.MSG_UNTREATED);
//        inbox.setReplyUrl("/devCluster/devices/devCluster/");
//        JsonObject jsonObject = new JsonObject();
//        jsonObject.addProperty("srcId", ownerId);
//        jsonObject.addProperty("destId", userId);
//        jsonObject.addProperty("cid", clusterId);
//        jsonObject.addProperty("name", name);
//        jsonObject.addProperty("deviceIds", String.valueOf(deviceIds));
//        inbox.setEncryptData(jsonObject.toString());
//        inbox.setOwnerId(userId);
//        inboxMapper.saveInbox(inbox);
//        simpMessagingTemplate.convertAndSendToUser(user2.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
//    }

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void replyTransferDev2DevCluster(Long ownerId, String username, MsgData msgData) {
//        // 检查用户是否拥有此消息
//        Inbox msgInfo = inboxMapper.getMsgInfo(msgData.getMsgId());
//        if (!msgInfo.getOwnerId().equals(ownerId)) {
//            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_MSG);
//        }
//        // 检查消息是否已经回复
//        if (!msgInfo.getReplyState().equals(Constant.MsgStatus.UNREPLY)) {
//            return;
//        }
//        JSONObject jsonObject = JSON.parseObject(msgInfo.getEncryptData());
//        if (!jsonObject.containsKey("srcId") || !jsonObject.containsKey("destId")
//                || !jsonObject.containsKey("cid") || !jsonObject.containsKey("name") || !jsonObject.containsKey(
//                "deviceIds")) {
//            throw new BusinessException(ResponseResult.JSON_PARSE_ERROR);
//        }
//        Long srcId = Long.valueOf(jsonObject.get("srcId").toString());
//        Long destId = Long.valueOf(jsonObject.get("destId").toString());
//        Long cid = Long.valueOf(jsonObject.get("cid").toString());
//        String name = jsonObject.get("name").toString();
//        JSONArray ids = jsonObject.getJSONArray("deviceIds");
//        List<Long> deviceIds = ids.toJavaList(Long.class);
//        // 校验是否是指定用户回的消息
//        if (!ownerId.equals(destId)) {
//            throw new BusinessException(ResponseResult.FORBIDDEN);
//        }
//        Inbox inbox = new Inbox();
//        inbox.setType(Constant.MsgType.EVENT);
//        inbox.setReaded(Constant.Msg.UNREADED);
//        inbox.setCreateDate(new Date());
//        inbox.setNeedReply(false);
//        inbox.setOwnerId(srcId);
//        inbox.setCode(Constant.WEBSOCKETCMD.REPLY_APPLY_TRANSFER_DEVICE_TO_DEVICE_CLUSTER);
//        User userInfoById = userService.getUserInfoById(srcId);
//        List<String> devNamesByIds = deviceMapper.getDevNamesByIds(deviceIds);
//        JSONObject json = new JSONObject();
//        json.put("deviceNames", devNamesByIds);
//        json.put("replyUsername", username);
//        json.put("role", Constant.DevClusterRole.OWNER);
//        if (msgData.getAnsCode().equals(Constant.MsgStatus.REFUSED)) {
//            inboxMapper.updateInboxReply(msgData.getMsgId(), Constant.MsgStatus.REFUSED);
//            json.put("ans", Constant.MsgStatus.REFUSED);
//            inbox.setContent(json.toString());
//            inboxMapper.saveInbox(inbox);
//            simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(),
//                    Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
//        } else if (msgData.getAnsCode().equals(Constant.MsgStatus.AGREE)) {
//            inboxMapper.updateInboxReply(msgData.getMsgId(), Constant.MsgStatus.AGREE);
//            // 检查移交设备群是否存在
//            DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
//            if (devClusterInfo == null) {
//                throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
//            }
//            // 检查被移交设备群是否存在
//            DeviceCluster devClusterInfoByName = deviceMapper.getDevClusterInfoByName(name);
//            if (devClusterInfoByName == null) {
//                throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
//            }
//            // 检查是否是移交设备群的群主
//            Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(srcId, cid);
//            if (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER)) {
//                throw new BusinessException(ResponseResult.DEVICE_CLUSTER_USER_NOT_OWNER, "用户id：" + srcId + ",设备群id：" + cid);
//            }
//            // 检查是否是被移交设备群的群主
//            Integer devClusterUserRole1 = deviceMapper.getDevClusterUserRole(ownerId, cid);
//            if (!devClusterUserRole1.equals(Constant.DevClusterRole.OWNER)) {
//                throw new BusinessException(ResponseResult.DEVICE_CLUSTER_USER_NOT_OWNER, "用户id：" + ownerId + ",设备群id：" + cid);
//            }
//            // 检查设备群用户是否是关联关系
//            User user1 = userService.getUserInfoById(ownerId);
//            if (user1 == null) {
//                throw new BusinessException(ResponseResult.USER_NOT_EXISTED, "id:" + ownerId);
//            }
//            User user2 = userService.getUserInfoById(srcId);
//            if (user2 == null) {
//                throw new BusinessException(ResponseResult.USER_NOT_EXISTED, "id:" + srcId);
//            }
//            userService.checkUserRelative(user1, user2);
//            // 检查设备是否都存在
//            List<Long> deviceIdByCid = deviceMapper.getDeviceIdByCid(cid);
//            if (deviceIdByCid == null) {
//                throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
//            }
//            deviceMapper.updateDevDevClusterByIds(devClusterInfoByName.getId(), deviceIds);
//            deviceMapper.updateDevDevClusterFromMicoByIds(devClusterInfoByName.getName(), deviceIds);
//            json.put("ans", Constant.MsgStatus.AGREE);
//            inbox.setContent(json.toString());
//            inboxMapper.saveInbox(inbox);
//            simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(),
//                    Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
////            for (Long id : deviceIds) {
////                if (!deviceIdByCid.contains(id)) {
////                    throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED);
////                }
////                deviceMapper.updateDevDevCluster(devClusterInfoByName.getId(), id);
////                deviceMapper.updateDevDevClusterFromMico(devClusterInfoByName.getName(), id);
////            }
//        } else {
//            throw new BusinessException(ResponseResult.MSG_ANSWER_CODE_ERROR);
//        }
//
//    }

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void claimDevCluster(Long uid, Long deviceId, String pwd) {
//        // 查询用户设备群
//        List<Long> devclusterIdByUserId = deviceMapper.getDevclusterIdByUserId(uid);
//        // 检查设备是否在用户设备群中
//        Device deviceInfoById = deviceMapper.getDeviceInfoById(deviceId);
//        if (deviceInfoById == null || !devclusterIdByUserId.contains(deviceInfoById.getDeviceClusterId())) {
//            throw new BusinessException(ResponseResult.DEVICE_NOT_IN_USER_DEVICE_CLUSTER,
//                    ",设备id: " + deviceId);
//        }
//        // 检查设备是否在线
//        Object online_info = redisUtils.hget("online_info", String.valueOf(deviceInfoById.getMicoDeviceId()));
//        if (online_info == null) {
//            throw new BusinessException(ResponseResult.DEVICE_NOT_ONLINE);
//        }
//        // 校验密码
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("code",Constant.RBTMQCMD.CLAIM_DEVICE);
//        jsonObject.put("userId",uid);
//        jsonObject.put("deviceId",deviceId);
//        jsonObject.put("password",pwd);
//        rabbitTemplate.convertAndSend(Constant.Rabbitmq.WEB_TO_CLIENT_EXCHANGE, Constant.Rabbitmq.WEB_TO_CLIENT_ROUTING_KEY,
//                jsonObject, message -> {
//                    message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
//                    return message;
//                });
//        // 检查设备是否已经认领
//        Long deviceIdByUserIdAndDeviceId = deviceMapper.getDeviceIdByUserIdAndDeviceId(uid, deviceId);
//        if (deviceIdByUserIdAndDeviceId != null) {
//            throw new BusinessException(ResponseResult.DEVICE_ALREADY_IN_MY_LIST);
//        }
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void authDev2Other(Long ownerId, List<Long> userIds, Long deviceId, Integer auth) {
        User implUser = userService.getUserInfoById(ownerId);
        // 检查设备是否存在
        Device deviceInfoById = deviceMapper.getDeviceInfoById(deviceId);
        if (deviceInfoById == null) {
            throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED);
        }
        // 检查授权用户是否在设备群
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(implUser.getId(), deviceInfoById.getDeviceClusterId());
        if (devClusterUserRole == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        }
        // 检查授权用户是否是群主或者管理员身份
        if (!Constant.DevClusterRole.OWNER.equals(devClusterUserRole) && !Constant.DevClusterRole.ADMIN.equals(devClusterUserRole)) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_ROLE_NOT_OWNER_OR_ADMIN);
        }
        // 检查用户id是否有重复
        long count = userIds.stream().distinct().count();
        if (count != userIds.size()) {
            throw new BusinessException(ResponseResult.LIST_CONTAIN_DUPLICATE_ID);
        }
        // 检查是否存在
        List<User> usersByUserIds = userMapper.getUsersByUserIds(userIds);
        if (usersByUserIds.size() != userIds.size()) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        // 检查用户是否是关联用户
        long adminId = implUser.getParentId() == 0 ? implUser.getId() : implUser.getParentId();
        for (User u : usersByUserIds) {
            if (u.getId() != adminId && u.getParentId() != adminId) {
                throw new BusinessException(ResponseResult.USER_NOT_RELATIVE);
            }
        }
        // 检查被授权用户是否在设备群
        Integer usersInDevCluster = deviceMapper.getUsersCountByUserIdsAndDevClusterId(userIds, deviceInfoById.getDeviceClusterId());
        if (usersInDevCluster != userIds.size()) {
            throw new BusinessException(ResponseResult.AUTHORIZED_USER_NOT_IN_DEVICE_CLUSTER);
        }
        // 授权
        if (auth.equals(Constant.Auth.OK)) {
            // 检查设备是否已授权
            Integer userCount = deviceMapper.getUsersCountFromMyDeviceByUserIdsAndDeviceId(userIds, deviceId);
            if (userCount != 0) {
                throw new BusinessException(ResponseResult.DEVICE_ALREADY_IN_MY_LIST);
            }
            deviceMapper.saveUsersDevice(userIds, deviceId);
        } else if (auth.equals(Constant.Auth.CANCEL)) { //取消授权
            // 检查设备是否已经取消授权
            Integer userCount = deviceMapper.getUsersCountFromMyDeviceByUserIdsAndDeviceId(userIds, deviceId);
            if (userCount != userIds.size()) {
                throw new BusinessException(ResponseResult.DEVICE_NOT_IN_MY_LIST);
            }
            deviceMapper.delUserDeviceByUserIdsAndDeviceId(userIds, deviceId);
        } else {
            throw new BusinessException(ResponseResult.DEVICE_AUTH_PARAM_ILLEGAL);
        }

        // 发消息给授权用户
        String content = null;
        if (auth.equals(Constant.Auth.OK)) {
            content = "用户：" + implUser.getUsername() + "将设备：" + deviceInfoById.getDeviceName() + "授权给您。";
        } else if (auth.equals(Constant.Auth.CANCEL)) {
            content = "用户：" + implUser.getUsername() + "取消授权设备：" + deviceInfoById.getDeviceName() + "给您。";
        }

        List<Inbox> inboxList = new ArrayList<>();
        for (User u : usersByUserIds) {
            Inbox inbox = new Inbox(u.getId(), Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
            inboxList.add(inbox);
        }
        inboxMapper.saveInboxes(inboxList);
        for (int i = 0; i < usersByUserIds.size(); i++) {
            simpMessagingTemplate.convertAndSendToUser(usersByUserIds.get(i).getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY,
                    inboxList.get(i));
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delDevices(Long uid, List<Long> deviceIds) {
        for (int i = 0; i < deviceIds.size(); i++) {
            // 获取设备群信息
            Device deviceInfoById = deviceMapper.getDeviceInfoById(deviceIds.get(i));
            if (deviceInfoById == null) {
                throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED);
            }
            if (deviceInfoById.getOnline()) {
                throw new BusinessException(ResponseResult.DEVICE_ONLINE_CAN_NOT_DELETE);
            }
            // 检查用户在设备群是否是群主
            Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(uid, deviceInfoById.getDeviceClusterId());
            if (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER)) {
                throw new BusinessException(ResponseResult.DEVICE_CLUSTER_USER_NOT_OWNER);
            }
        }
        // 通知拥有此设备的用户
        List<UserDeviceVO> userDevicesByDeviceIds = deviceMapper.getUserDevicesByDeviceIds(deviceIds);
        Map<Long, List<String>> userIdDevNames = new HashMap<>();
        for (UserDeviceVO u : userDevicesByDeviceIds) {
            List<String> orDefault = userIdDevNames.getOrDefault(u.getUserId(), new ArrayList<>());
            orDefault.add(u.getDeviceName());
            userIdDevNames.put(u.getUserId(), orDefault);
        }
        List<Inbox> inboxList = new ArrayList<>();
        for (Map.Entry<Long, List<String>> entry : userIdDevNames.entrySet()) {
            String content = "您删除了以下设备：" + entry.getValue();
            Inbox inbox = new Inbox(entry.getKey(), Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
            inboxList.add(inbox);
        }
        if (!inboxList.isEmpty()) {
            inboxMapper.saveInboxes(inboxList);
        }
        for (int j = 0; j < inboxList.size(); j++) {
            User userInfoById = userService.getUserInfoById(inboxList.get(j).getOwnerId());
            if (userInfoById != null) {
                simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(),
                        Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inboxList.get(j));
            }
        }

        // 更新网页设备删除标志
        deviceMapper.updateDevFromDevClusterByIds(deviceIds, Constant.DELETE_FLAG.DELETED);
        // 从我的设备列表删除
        deviceMapper.delUserDeviceByDevIds(deviceIds);
        // 获取使用此设备的场景
        List<Scene> sceneByDeviceIds = deviceMapper.getSceneByDeviceIds(deviceIds);
        // 删除场景连接中的设备
        sceneMapper.updateSceneConnectDeviceId(deviceIds);
        // 删除mico中设备
        deviceMapper.deleteMicoDevices(deviceIds, Constant.DELETE_FLAG.DELETED);
        // 停止场景运行
        for (Scene s : sceneByDeviceIds) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userId", s.getOwnerId());
            jsonObject.put("sceneId", s.getId());
            jsonObject.put("code", Constant.RBTMQCMD.STOP_SCENE);
//            if (s.getState().compareTo(Constant.SceneStatus.RUNNING) < 0) {
//                continue;
//            }
//            sceneMapper.updateSceneState(s.getId(), Constant.SceneStatus.PUBLIC);
            rabbitTemplate.convertAndSend(Constant.Rabbitmq.WEB_TO_CLIENT_EXCHANGE,
                    Constant.Rabbitmq.WEB_TO_CLIENT_ROUTING_KEY,
                    jsonObject, message -> {
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        return message;
                    });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void authDevClusterUser(Long ownerId, Long cid, Long uid, Integer rid) {
        User userInfoById = userService.getUserInfoById(uid);
        if (userInfoById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        // 校验设备群是否存在
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        // 检查授权用户是否是群主
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(ownerId, cid);
        if (devClusterUserRole == null || !devClusterUserRole.equals(Constant.DevClusterRole.OWNER)) {
            throw new BusinessException(ResponseResult.FORBIDDEN);
        }
        // 检查被授权用户是否在设备群
        Integer devClusterUserRole1 = deviceMapper.getDevClusterUserRole(uid, cid);
        if (devClusterUserRole1 == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        }
        // 检查设备群角色id是否合法
        if (!rid.equals(Constant.DevClusterRole.ADMIN) && !rid.equals(Constant.DevClusterRole.USER)) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_ROLE_ILLEGAL);
        }
        deviceMapper.updateDevClusterUserInfo(uid, cid, rid);
        String roleName = null;
        if (rid.equals(Constant.DevClusterRole.OWNER)) {
            roleName = "群主";
        } else if (rid.equals(Constant.DevClusterRole.ADMIN)) {
            roleName = "管理员";
        } else if (rid.equals(Constant.DevClusterRole.USER)) {
            roleName = "用户";
        }
        String content = "您在设备群：" + devClusterInfo.getName() + "的角色被变更为：" + roleName + "。";
        Inbox inbox = new Inbox(uid, Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
    }

    @Override
    public void inviteDevClusterUser(Long uid, Long cid, String name) {
        // 校验设备群是否存在
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        User implUser = userService.getUserInfoById(uid);
        // 检查邀请用户是否是群主或者管理员
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(implUser.getId(), cid);
        if (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER) && !devClusterUserRole.equals(Constant.DevClusterRole.ADMIN)) {
            throw new BusinessException(ResponseResult.FORBIDDEN);
        }
        User userByUsername = userMapper.getUserByUsername(name);
        if (userByUsername == null) {
            throw new BusinessException(ResponseResult.USERNAME_NOT_EXISTED);
        }
        // 检查邀请用户是否在设备群
        Integer devClusterUserRole1 = deviceMapper.getDevClusterUserRole(userByUsername.getId(), cid);
        if (devClusterUserRole1 != null) {
            throw new BusinessException(ResponseResult.USER_ALREADY_IN_DEV_CLUSTER);
        }
        // 检查受邀用户是否是关联关系
        userService.checkUserRelative(implUser, userByUsername);
        Inbox inbox = new Inbox();
        inbox.setType(Constant.MsgType.EVENT);
        inbox.setCreateDate(new Date());
        inbox.setReaded(Constant.Msg.UNREADED);
        String content = "用户：" + implUser.getUsername() + "邀请您加入设备群：" + devClusterInfo.getName() + "。";
        inbox.setContent(content);
        inbox.setCode(Constant.WEBSOCKETCMD.COMMON_MESSAGE);
        inbox.setNeedReply(true);
        inbox.setReplyState(Constant.MSG_UNTREATED);
        inbox.setReplyUrl("/devCluster/invite/reply");
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("srcId", implUser.getId());
        jsonObject.addProperty("destId", userByUsername.getId());
        jsonObject.addProperty("cid", cid);
        inbox.setEncryptData(jsonObject.toString());
        inbox.setOwnerId(userByUsername.getId());
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(userByUsername.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY
                , inbox);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replyInviteDevClusterUser(Long uid, MsgData msgData) {
        // 检查用户是否拥有此消息
        Inbox msgInfo = inboxMapper.getMsgInfo(msgData.getMsgId());
        if (!msgInfo.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_MSG);
        }
        // 检查消息是否已经回复
        if (!msgInfo.getReplyState().equals(Constant.MsgStatus.UNREPLY)) {
            return;
        }
        JSONObject jsonObject = JSON.parseObject(msgInfo.getEncryptData());
        if (!jsonObject.containsKey("srcId") || !jsonObject.containsKey("destId") || !jsonObject.containsKey("cid")) {
            throw new BusinessException(ResponseResult.JSON_PARSE_ERROR);
        }
        Long srcId = Long.valueOf(jsonObject.get("srcId").toString());
        Long destId = Long.valueOf(jsonObject.get("destId").toString());
        Long cid = Long.valueOf(jsonObject.get("cid").toString());
        User implUser = userService.getUserInfoById(uid);
        // 检查用户id是否被邀请用户id
        if (!implUser.getId().equals(destId)) {
            throw new BusinessException(ResponseResult.MSG_REPLY_USER_NOT_MATCH);
        }
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
        // 用户回复同意or拒绝
        User userInfoById = userService.getUserInfoById(srcId);
        Inbox inbox = new Inbox(srcId, Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE,
                "");
        if (msgData.getAnsCode().equals(Constant.MsgStatus.REFUSED)) {
            inboxMapper.updateInboxReply(msgData.getMsgId(), Constant.MsgStatus.REFUSED);
            inbox.setContent("用户：" + implUser.getUsername() + "拒绝了您邀请加入设备群：" + devClusterInfo.getName() + "的请求。");
            // 保存消息，发往消息队列
            inboxMapper.saveInbox(inbox);
            simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(),
                    Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
        } else if (msgData.getAnsCode().equals(Constant.MsgStatus.AGREE)) {
            inbox.setContent("用户：" + implUser.getUsername() + "同意了您邀请加入设备群：" + devClusterInfo.getName() + "的请求。");
            inboxMapper.updateInboxReply(msgData.getMsgId(), Constant.MsgStatus.AGREE);
            // 检查邀请用户是否在设备群
            Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(implUser.getId(), cid);
            if (devClusterUserRole != null) {
                throw new BusinessException(ResponseResult.USER_ALREADY_IN_DEV_CLUSTER);
            }
            deviceMapper.saveUserDevClusterInfo(implUser.getId(), cid, Constant.DevClusterRole.USER);

            // 保存消息，发往消息队列
            inboxMapper.saveInbox(inbox);
            simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(),
                    Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
        } else {
            throw new BusinessException(ResponseResult.MSG_ANSWER_CODE_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delDevClusterUser(Long ownerId, Long cid, Long uid) {
        User implUser = userService.getUserInfoById(ownerId);
        // 校验设备群是否存在
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        // 检查用户是否在设备群
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(implUser.getId(), cid);
        if (devClusterUserRole == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        }
        User userInfoById = userService.getUserInfoById(uid);
        if (userInfoById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        Integer devClusterUserRole1 = deviceMapper.getDevClusterUserRole(uid, cid);
        if (devClusterUserRole1 == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        }
        // 检查剔除用户与被踢出用户的角色是否合法,要求角色高一级
        if ((devClusterUserRole.equals(Constant.DevClusterRole.OWNER) && devClusterUserRole1.equals(Constant.DevClusterRole.OWNER)) ||
                (devClusterUserRole.equals(Constant.DevClusterRole.ADMIN) && devClusterUserRole1.equals(Constant.DevClusterRole.OWNER) ||
                        devClusterUserRole1.equals(Constant.DevClusterRole.ADMIN))) {
            throw new BusinessException(ResponseResult.FORBIDDEN);
        }
        deviceMapper.delDevClusterUserByUserIdAndDevClusterId(cid, uid);
        // 删除从设备群授权或者认领的设备
        deviceMapper.delUserDeviceByDevClusterIdAndUserId(cid, uid);
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("deviceClusterName", devClusterInfo.getName());
//        jsonObject.put("deviceClusterAdminOrOwner", implUser.getUsername());
//        jsonObject.put("role", devClusterUserRole);
        String content = "您被管理员：" + implUser.getUsername() + "踢出了设备群：" + devClusterInfo.getName() + "。";
        Inbox inbox = new Inbox(uid, Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void quitDevCluster(Long uid, Long cid) {
        User implUser = userService.getUserInfoById(uid);
        // 校验设备群是否存在
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        // 检查用户是否在设备群,且不是群主
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(implUser.getId(), cid);
        if (devClusterUserRole == null) {
            throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
        } else if (devClusterUserRole.equals(Constant.DevClusterRole.OWNER)) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_OWNER_CAN_NOT_QUIT);
        }
        deviceMapper.delUserDeviceByDevClusterIdAndUserId(cid, implUser.getId());
        deviceMapper.delDevClusterUser(implUser.getId(), cid);
        // 发消息
        String content = "用户：" + implUser.getUsername() + "退出了设备群：" + devClusterInfo.getName() + "。";
        Inbox inbox = new Inbox(implUser.getId(), Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(implUser.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY,
                inbox);
    }

    @Override
    public PageResult findDevCluster(PageRequest pageRequest, Long uid, String name) {
        User implUser = userService.getUserInfoById(uid);
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        Long adminId = null;
        if (implUser.getParentId() == 0L) {
            adminId = implUser.getId();
        } else {
            adminId = implUser.getParentId();
        }
        List<DeviceCluster> devClusterInfoByName = deviceMapper.getDevClusterInfoByNameAndRole(adminId, name);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(devClusterInfoByName));
    }

    @Override
    public PageResult getMyDevicesInfo(PageRequest pageRequest, Long uid) {
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<Device> myDeviceInfo = deviceMapper.getMyDeviceInfo(uid);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(myDeviceInfo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delMyDevices(Long uid, List<Long> deviceIds) {
        // 检查设备是否都是我的设备
        for (Long id : deviceIds) {
            Long deviceIdByUserIdAndDeviceId = deviceMapper.getDeviceIdByUserIdAndDeviceId(uid, id);
            if (deviceIdByUserIdAndDeviceId == null) {
                throw new BusinessException(ResponseResult.DEVICE_NOT_IN_MY_LIST.getCode(),
                        ResponseResult.DEVICE_NOT_IN_MY_LIST.getMessage() + ",id:" + id);
            }
            deviceMapper.delMyDevice(uid, id);
        }

        // 获取设备名
        List<String> deviceNamesByIds = deviceMapper.getDeviceNamesByIds(deviceIds);
        // 通知用户设备从我的列表删除
        StringBuilder content = new StringBuilder("您删除了以下设备：");
        for (int i = 0; i < deviceNamesByIds.size(); i++) {
            content.append(deviceNamesByIds.get(i));
            if (i == deviceNamesByIds.size() - 1) {
                content.append('.');
            } else {
                content.append(',');
            }
        }
        Inbox inbox = new Inbox(uid, Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content.toString());
        inboxMapper.saveInbox(inbox);
        User userInfoById = userService.getUserInfoById(uid);
        simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(),
                Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);

        // 从我的设备列表删除
        deviceMapper.delUserDeviceByUidAndDevIds(uid, deviceIds);
        // 获取使用此设备的且属于我的场景
        List<Scene> sceneByDeviceIds = deviceMapper.getSceneByUidAndDeviceIds(uid, deviceIds);
        // 删除场景连接中的设备
        sceneMapper.updateSceneConnectDeviceId(deviceIds);
        // 停止场景运行
        for (Scene s : sceneByDeviceIds) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userId", s.getOwnerId());
            jsonObject.put("sceneId", s.getId());
            jsonObject.put("code", Constant.RBTMQCMD.STOP_SCENE);
//            if (s.getState().compareTo(Constant.SceneStatus.RUNNING) < 0) {
//                continue;
//            }
//            sceneMapper.updateSceneState(s.getId(), Constant.SceneStatus.PUBLIC);
            rabbitTemplate.convertAndSend(Constant.Rabbitmq.WEB_TO_CLIENT_EXCHANGE,
                    Constant.Rabbitmq.WEB_TO_CLIENT_ROUTING_KEY,
                    jsonObject, message -> {
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        return message;
                    });
        }
    }

    @Override
    public Device getDeviceInfo(Long uid, Long deviceId) {
        // 检查设备是否存在
        Device deviceInfoById = deviceMapper.getDeviceInfoById(deviceId);
        if (deviceInfoById == null) {
            throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED);
        }
        // 检查用户是否在包含此设备的设备群
        Integer devClusterUserRoleByUserIdAndDevId = deviceMapper.getDevClusterUserRoleByUserIdAndDevId(uid, deviceId);
        if (devClusterUserRoleByUserIdAndDevId == null) {
            throw new BusinessException(ResponseResult.DEVICE_NOT_IN_MY_LIST);
        }
        return deviceInfoById;
    }

    @Override
    public void updateDeviceInfo(Long uid, Device device) {
        // 检查设备是否存在
        Device deviceInfoById = deviceMapper.getDeviceInfoById(device.getId());
        if (deviceInfoById == null) {
            throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED);
        }
        // 检查用户是否在包含此设备的设备群,且是群主
        Integer devClusterUserRoleByUserIdAndDevId =
                deviceMapper.getDevClusterUserRoleByUserIdAndDevId(uid, device.getId());
        if (devClusterUserRoleByUserIdAndDevId == null ||
                !devClusterUserRoleByUserIdAndDevId.equals(Constant.DevClusterRole.OWNER)) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_USER_NOT_OWNER);
        }
        deviceMapper.updateDeviceInfo(device);
    }

    @Override
    public PageResult getDevClusterDevInfo(PageRequest pageRequest, Integer state,
                                           String search, String sort, Long ownerId, Long cid) {
        // 检查用户是否有此用户群
        getDevClusterInfo(ownerId, cid);
        // 校验sort字段
        checkSortField(sort, DEVICESORTFIELD);
        // 校验state
        if (state != null && !state.equals(Constant.DevStatus.OFFLINE) && !state.equals(Constant.DevStatus.ONLINE)) {
            throw new BusinessException(ResponseResult.DEVICE_STATE_ERROR);
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<Device> devices = deviceMapper.getDevClusterDevInfo(cid, search, state, sort);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(devices));
    }

    /**
     * 校验sort字段是否合法
     *
     * @param sort
     * @param deviceSortField
     * @return: void
     */
    private void checkSortField(String sort, String[] deviceSortField) {
        // 校验sort字段
        if (StringUtils.hasLength(sort)) {
            List<String> list = Arrays.asList(deviceSortField);
            String[] s = sort.split("\\s+");
            if (s.length != 2 || !list.contains(s[0]) || !"desc".equalsIgnoreCase(s[1])
                    && !"asc".equalsIgnoreCase(s[1])) {
                throw new BusinessException(ResponseResult.SORT_FIELD_FORMAT_ERROR);
            }
        }
    }

    @Override
    public PageResult getDevInfoFromMico(User implUser, String username, String password, PageRequest pageRequest,
                                         String sort, String search) {
        // 必须是管理员
        if (implUser.getParentId() != 0L) {
            throw new BusinessException(ResponseResult.USER_NOT_ADMIN);
        }
        // 校验用户名和密码
        String micoUserPwdByName = userMapper.getMicoUserPwdByName(username);
        if (micoUserPwdByName == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        String s = DigestUtils.md5Hex(password.getBytes());
        if (!s.equalsIgnoreCase(micoUserPwdByName)) {
            throw new BusinessException(ResponseResult.PASSWORD_ERROR);
        }
        // 校验sort字段
        checkSortField(sort, MICODEVICESORTFIELD);
        // 获取账号所有设备群中所有的设备
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<MicoDevice> devices = deviceMapper.getMicoDevInfo(username, sort, search);
        for (MicoDevice m : devices) {
            Object onlineInfo = redisUtils.hget("online_info", String.valueOf(m.getDeviceId()));
            if (onlineInfo != null) {
                m.setOnline(true);
            } else {
                m.setOnline(false);
            }
        }
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(devices));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDevicesFromMico(User implUser, String username, String password, Long cid, List<Long> deviceIds) {
        // 必须是管理员
        if (implUser.getParentId() != 0L) {
            throw new BusinessException(ResponseResult.USER_NOT_ADMIN);
        }
        // 校验用户名和密码
        String micoUserPwdByName = userMapper.getMicoUserPwdByName(username);
        if (micoUserPwdByName == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        String s = DigestUtils.md5Hex(password.getBytes());
        if (!s.equalsIgnoreCase(micoUserPwdByName)) {
            throw new BusinessException(ResponseResult.PASSWORD_ERROR);
        }
        // 检查设备群id
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(implUser.getId(), cid);
        if (devClusterUserRole == null) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_DEVICE_CLUSTER);
        }
        // 获取账号所有的设备信息
        List<MicoDevice> devices = deviceMapper.getMicoDevInfo(username, "", "");
        Map<Long, MicoDevice> idMicoDevice = new HashMap<>();
        for (MicoDevice m : devices) {
            idMicoDevice.put(m.getDeviceId(), m);
        }
        List<Device> webDevices = new ArrayList<>();
        List<String> devNamesByIds = new ArrayList<>();
        Set<Long> set = new HashSet<>();
        // 新设备是指第一次从mico导入网页的设备，所以需要插入网页设备
        // 老设备是指已经导入过的设备，再经过导回mico的设备群或者删除设备操作的设备,此时数据库中设备id已经有了关联，所以修改网页设备即可
        List<Device> newDevices = new ArrayList<>();
        List<Device> oldDevices = new ArrayList<>();
        // 校验导入的设备
        for (Long id : deviceIds) {
            // 检查是否有重复id
            if (set.contains(id)) {
                throw new BusinessException(ResponseResult.DEVICE_ID_DUPLICATE);
            }
            set.add(id);
            // 检查设备id是否是mico客户端的
            if (!idMicoDevice.containsKey(id)) {
                throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED_IN_MICO);
            }
            // 检查是否已经导入
            if (idMicoDevice.get(id).getDeleteFlag() != null && idMicoDevice.get(id).getDeleteFlag() == 0) {
                throw new BusinessException(ResponseResult.DEVICE_ALREADY_IMPORT);
            }
            devNamesByIds.add(idMicoDevice.get(id).getDeviceName());
            Device device = new Device();
            device.setCreateDate(new Date());
            device.setDeviceClusterId(cid);
            device.setDeviceName(idMicoDevice.get(id).getDeviceName());
            device.setDescription("从mico客户端导入");
            device.setMacAddr(idMicoDevice.get(id).getMacAddr());
            device.setMicoDeviceId(idMicoDevice.get(id).getDeviceId());
            Object onlineInfo = redisUtils.hget("online_info", String.valueOf(id));
            if (onlineInfo == null) {
                device.setOnline(false);
            } else {
                device.setOnline(true);
            }
//            webDevices.add(device);
            if (idMicoDevice.get(id).getDeleteFlag() == null) {
                newDevices.add(device);
            } else {
                oldDevices.add(device);
            }
        }
        // 删除deleteFlag为1的设备，以防micoDeviceID重复
//        deviceMapper.delDevicesAlreadyDelete(deviceIds, 1);

        if (!newDevices.isEmpty()) {
            deviceMapper.saveDevices(newDevices);
        }
        if (!oldDevices.isEmpty()) {
            deviceMapper.updateDevices(oldDevices);
        }
        // 发消息给用户
        String content = "您从mico客户端导入了以下设备：" + devNamesByIds + "。";
        Inbox inbox = new Inbox(implUser.getId(), Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(implUser.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyJoinDevCluster(Long uid, Long cid) {
        Long ownerId = deviceMapper.getDevClusterOwnerIdByCidAndRole(cid, Constant.DevClusterRole.OWNER);
        if (ownerId == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_OWNER_EMPTY);
        }
        User applyUser = userService.getUserInfoById(uid);
        User devOwnerUser = userService.getUserInfoById(ownerId);
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
        // 检查设备群是否存在
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }
        // 检查设备群的群主是否是关联账号
        if (!(applyUser.getParentId().equals(devOwnerUser.getParentId())
                || applyUser.getParentId().equals(devOwnerUser.getId())
                || devOwnerUser.getParentId().equals(applyUser.getId()))) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_OWNER_NOT_RELATIVE_USER);
        }
        // 检查用户是否已在设备群
        Integer devClusterRoleByUidAndCid = deviceMapper.getDevClusterRoleByUidAndCid(uid, cid);
        if (devClusterRoleByUidAndCid != null) {
            throw new BusinessException(ResponseResult.USER_ALREADY_IN_DEV_CLUSTER);
        }
        // 发消息给设备群群主和管理员
        List<User> devClusterOwnerAndAdminUserInfo = deviceMapper.getDevClusterOwnerAndAdminUserInfo(cid,
                Constant.DevClusterRole.USER);
        Inbox inbox = new Inbox();
        inbox.setType(Constant.MsgType.EVENT);
        inbox.setCreateDate(new Date());
        inbox.setReaded(Constant.Msg.UNREADED);
        inbox.setCode(Constant.WEBSOCKETCMD.COMMON_MESSAGE);
        inbox.setContent("用户：" + applyUser.getUsername() + "申请加入设备群：" + devClusterInfo.getName() + "。");
        inbox.setNeedReply(true);
        inbox.setReplyState(Constant.MSG_UNTREATED);
        inbox.setReplyUrl("/devCluster/join/reply");
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("srcId", uid);
        jsonObject.addProperty("cid", cid);
        for (int i = 0; i < devClusterOwnerAndAdminUserInfo.size(); i++) {
            inbox.setOwnerId(devClusterOwnerAndAdminUserInfo.get(i).getId());
            inbox.setEncryptData(jsonObject.toString());
            inboxMapper.saveInbox(inbox);
            // 发给客户端的消息不需要携带消息内容
            inbox.setEncryptData("");
            simpMessagingTemplate.convertAndSendToUser(devClusterOwnerAndAdminUserInfo.get(i).getUsername(),
                    Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox.toString());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replyApplyJoinDevCluster(Long uid, MsgData msgData) {
        // 检查消息是否是用户的
        Inbox msgInfo = inboxMapper.getMsgInfo(msgData.getMsgId());
        if (msgInfo == null || !msgInfo.getOwnerId().equals(uid)) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_MSG);
        }
        // 检查消息是否已回复
        if (!msgInfo.getReplyState().equals(Constant.MsgStatus.UNREPLY)) {
            return;
        }
//        // 检查消息url是否正确
//        if ("/devCluster/join/reply".equals(msgInfo.getReplyUrl())) {
//            throw new BusinessException(ResponseResult.MSG_URL_ERROR);
//        }
        // 解析json数据
        JSONObject jsonObject = JSON.parseObject(msgInfo.getEncryptData());
        if (!jsonObject.containsKey("srcId") || !jsonObject.containsKey("cid")) {
            throw new BusinessException(ResponseResult.JSON_PARSE_ERROR);
        }
        Long srcId = Long.valueOf(jsonObject.get("srcId").toString());
        Long cid = Long.valueOf(jsonObject.get("cid").toString());

        // 检查设备群是否存在
        DeviceCluster devClusterInfo = deviceMapper.getDevClusterInfo(cid);
        if (devClusterInfo == null) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_NOT_EXISTED);
        }

        // 检查申请用户是否已在设备群
        Integer devClusterRoleByUidAndCid = deviceMapper.getDevClusterRoleByUidAndCid(srcId, cid);
        if (devClusterRoleByUidAndCid != null) {
            throw new BusinessException(ResponseResult.USER_ALREADY_IN_DEV_CLUSTER);
        }

        // 检查用户是否还是群主或者管理员
        Integer devClusterUserRole = deviceMapper.getDevClusterUserRole(uid, cid);
        if (devClusterUserRole == null || (!devClusterUserRole.equals(Constant.DevClusterRole.OWNER) &&
                !devClusterUserRole.equals(Constant.DevClusterRole.ADMIN))) {
            throw new BusinessException(ResponseResult.DEVICE_CLUSTER_ROLE_NOT_OWNER_OR_ADMIN);
        }

        if (msgData.getAnsCode().equals(Constant.MsgStatus.AGREE)) {
            deviceMapper.saveUserDevClusterInfo(srcId, cid, Constant.DevClusterRole.USER);
            msgInfo.setReaded(Constant.Msg.READED);
            msgInfo.setReplyState(Constant.MsgStatus.AGREE);
            inboxMapper.updateInboxReadedAndState(msgInfo);
            // 给申请者发通过消息，拒绝不发消息，因为还有其他管理员可以同意
            String content = "管理员同意了您申请加入设备群：" + devClusterInfo.getName() + "的请求。";
            Inbox inbox = new Inbox(srcId, Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
            inboxMapper.saveInbox(inbox);
            User userInfoById = userService.getUserInfoById(srcId);
            simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(),
                    Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
        } else if (msgData.getAnsCode().equals(Constant.MsgStatus.REFUSED)) {
            inboxMapper.updateInboxReply(msgInfo.getId(), Constant.MsgStatus.REFUSED);
            msgInfo.setReaded(Constant.Msg.READED);
            msgInfo.setReplyState(Constant.MsgStatus.REFUSED);
            inboxMapper.updateInboxReadedAndState(msgInfo);
        } else {
            throw new BusinessException(ResponseResult.MSG_ANSWER_CODE_ERROR);
        }
    }

    @Override
    public PageResult getDeviceAuthorityUsers(User implUser, Long deviceId, Integer auth, PageRequest pageRequest) {
        // 检查设备是否存在
        Device deviceInfoById = deviceMapper.getDeviceInfoById(deviceId);
        if (deviceInfoById == null) {
            throw new BusinessException(ResponseResult.DEVICE_NOT_EXISTED);
        }
        // 检查授权参数是否合法
        if (!auth.equals(Constant.Auth.OK) && !auth.equals(Constant.Auth.CANCEL)) {
            throw new BusinessException(ResponseResult.DEVICE_AUTH_PARAM_ILLEGAL);
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<User> deviceAuthUsers = deviceMapper.getDeviceAuthUsers(deviceInfoById.getDeviceClusterId(), deviceId, auth);
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(deviceAuthUsers));
    }
}